package com.ts.code.creator.creator.impl;

import com.intellij.notification.NotificationGroupManager;
import com.intellij.notification.NotificationType;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.JavaDirectoryService;
import com.intellij.psi.PsiAnnotation;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiClassType;
import com.intellij.psi.PsiDirectory;
import com.intellij.psi.PsiElementFactory;
import com.intellij.psi.PsiJavaFile;
import com.intellij.psi.PsiManager;
import com.intellij.psi.PsiMethod;
import com.intellij.psi.codeStyle.JavaCodeStyleManager;
import com.intellij.psi.search.GlobalSearchScope;
import com.ts.code.creator.creator.CodeCreator;
import com.ts.code.creator.enums.CreateFileEnum;
import com.ts.code.creator.creator.ClassFileSearch;
import com.ts.code.creator.util.CreateCodeContext;
import org.apache.commons.lang3.StringUtils;

public abstract class AbstractCodeCreator implements CodeCreator {
    protected final CreateCodeContext context;
    protected final PsiElementFactory factory;
    protected final ClassFileSearch classFileSearch;

    public AbstractCodeCreator(CreateCodeContext context) {
        this.context = context;
        classFileSearch = new ClassFileSearch(context);
        factory = PsiElementFactory.SERVICE.getInstance(context.getProject());
    }

    // 给java文件增加方法
    protected void addMethod(String javaFile, String method) {
        PsiClass psiClass = getPsiClass(javaFile);
        if (psiClass != null) {
            PsiMethod psiMethod = factory.createMethodFromText(method, null);
            PsiMethod[] methodsByNames = psiClass.findMethodsByName(psiMethod.getName(), true);
            // 方法不存在才创建
            if (methodsByNames.length == 0 || context.isExistCreateMethod()) {
                psiClass.add(psiMethod);
            }

            // import
            JavaCodeStyleManager.getInstance(context.getProject()).shortenClassReferences(psiClass);
        }
    }

    protected PsiClass getPsiClass(String javaFile) {
        VirtualFile virtualFile = LocalFileSystem.getInstance().findFileByPath(javaFile);
        if (virtualFile != null) {
            PsiJavaFile psi = (PsiJavaFile) PsiManager.getInstance(context.getProject()).findFile(virtualFile);

            PsiClass[] classes = psi.getClasses();
            if (classes != null && classes.length > 0) {
                return classes[0];
            }
        }
        return null;
    }

    protected PsiClass createClass(String classDir, String className, String extendClass) {
        Project project = context.getProject();

        VirtualFile fileDir = LocalFileSystem.getInstance().findFileByPath(classDir);
        PsiDirectory directory = PsiManager.getInstance(context.getProject()).findDirectory(fileDir);

        try {
            // 检查下是否可以在当前目录下创建指定类名的类
            JavaDirectoryService.getInstance().checkCreateClass(directory, className);
        } catch (Exception exception) {
            // 错误通知，右下角小弹框 (Balloon) UI :https://www.ideaplugin.com/idea-docs/Part%20II%20%E2%80%94%20Base%20Platform/User%20Interface%20Components/Notifications.html#_2020-3-%E5%92%8C%E4%B9%8B%E5%90%8E%E7%9A%84%E7%89%88%E6%9C%AC
            // 可以新建个同类名看下效果
            NotificationGroupManager.getInstance()
                    // plugin.xml里配置的id
                    .getNotificationGroup("code create group")
                    .createNotification(exception.getMessage(), NotificationType.ERROR)
                    .notify(project);
            return null;
        }

        // 创建class
        PsiClass psiClass = JavaDirectoryService.getInstance().createClass(directory, className);

        // 添加注解
        PsiAnnotation annotation = psiClass.getModifierList().addAnnotation("lombok.Data");

        // import
        if (StringUtils.isNotBlank(extendClass)) {
            PsiClassType pageRequestParamType = PsiClassType.getTypeByName(extendClass, project, GlobalSearchScope.allScope(project));
            psiClass.getExtendsList().add(factory.createReferenceElementByType(pageRequestParamType));
        }

        // 短类名引用, 自动 import lombok.Data; 并使用 @Data
        JavaCodeStyleManager.getInstance(project).shortenClassReferences(annotation);

        return psiClass;
    }

    protected String adminParam() {
        String paramStr = "";
        switch (context.getParamTypeEnum()) {
            case NONE:
                paramStr = "";
                break;
            case ID:
                paramStr = "IdParam param";
                break;
            case PAGE:
            case COMMON:
                paramStr = adminParamClass() + " param";
        }
        return paramStr;
    }

    protected String className(String suffix) {
        return classFileSearch.className(suffix);
    }

    // admin param的全限定名
    protected String adminParamClass() {
        return classFileSearch.adminPackage() + ".param." + className("Param");
    }

    // admin vo的全限定名
    protected String adminVOClass() {
        return classFileSearch.adminPackage() + ".vo." + className("VO");
    }

    // provider reqDTO 的全限定名
    protected String reqDTOClass() {
        return classFileSearch.providerDTOPackage() + "." + className("ReqDTO");
    }

    // provider respDTO 的全限定名
    protected String respDTOClass() {
        return classFileSearch.providerDTOPackage() + "." + className("RespDTO");
    }

    protected String adminVO() {
        // 返回类型
        String returnType = "";
        switch (context.getRetTypeEnum()) {
            case NULL:
                returnType = "NullVO";
                break;
            case ID:
                returnType = "IdVO";
                break;
            case LIST:
                returnType = "List<" + adminVOClass() + ">";
                break;
            case PAGE:
                returnType = "PageVO<" + adminVOClass() + ">";
                break;
            case COMMON:
                returnType = adminVOClass();
        }
        return returnType;
    }

    protected String reqDTO() {
        String paramStr = "";
        switch (context.getParamTypeEnum()) {
            case NONE:
                paramStr = "";
                break;
            case ID:
                paramStr = "IdReqDTO reqDTO";
                break;
            case PAGE:
            case COMMON:
                paramStr = reqDTOClass() + " reqDTO";
        }
        return paramStr;
    }

    protected String respDTO() {
        // 返回类型
        String returnType = "";
        switch (context.getRetTypeEnum()) {
            case NULL:
                returnType = "NullRespDTO";
                break;
            case ID:
                returnType = "IdRespDTO";
                break;
            case LIST:
                returnType = "List<" + respDTOClass() + ">";
                break;
            case PAGE:
                returnType = "PageDTO<" + respDTOClass() + ">";
                break;
            case COMMON:
                returnType = respDTOClass();
        }
        return returnType;
    }

    // 备注
    protected String remark(String paramName) {
        // /**
        //     * 单个查询
        //     *
        //     * @param reqDTO 参数
        //     * @return 结果
        //     */
        String text = "/**\n";
        text += "     * " + context.getRemark() + "\n";
        text += "     *\n";
        switch (context.getParamTypeEnum()) {
            case NONE:
                break;
            case ID:
            case PAGE:
            case COMMON:
                text += String.format("     * @param %s 请求参数\n", paramName);
        }
        text += "     * @return 结果\n";
        text += "     */\n";
        return text;
    }

    @Override
    public void create() {
        if (context.getCreateFileTypes().contains(createFileEnum())) {
            doCreate();
        }
    }

    protected abstract CreateFileEnum createFileEnum();

    protected abstract void doCreate();

}
